package com.xcode.unit.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xcode.unit.model.MethodModel;
import com.xcode.unit.model.ParameterModel;
import com.xcode.unit.model.SourceClassModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import javax.jws.soap.SOAPBinding;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author liuziying
 * @Description 反射工具类
 * @Date 2020/12/24
 */
public class LReflectionUtils {
    static Logger logger = LoggerFactory.getLogger(LReflectionUtils.class);

    private LReflectionUtils(){}

    /**
     * 忽略Mock的字段
     */
    static List<String> ignoreField = Lists.newArrayList("log");

    /**
     * 获取类变量-(字段名, 字段类型)
     * @param clazz
     * @return
     */
    public static Map<String,Type> getClassFields(Class clazz){
        Map<String,Type> classField = Maps.newHashMap();
        try {
            Object obj = clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields){
                String fieldName = field.getName();
                if(ignoreField.contains(fieldName)){
                    continue;
                }
                Type fieldType = field.getGenericType();
                classField.put(fieldName, fieldType);
            }
            return classField;
        } catch (IllegalAccessException e) {
            logger.error("无法访问实体" + clazz.getName(),e);
        } catch (InstantiationException e) {
            logger.error("实例化实体"+ clazz.getName()+"出错",e);
        }
        return null;
    }

    /**
     * 获取类方法(方法名-属性集)
     * @param clazz
     * @return
     */
    public static Map<String, MethodModel> getMethods(Class clazz){
        Map<String, MethodModel> methods = Maps.newHashMap();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        MethodModel methodModel;
        for (Method method : declaredMethods) {
            methodModel = new MethodModel();
            methodModel.setMethodName(method.getName());
            methodModel.setReturnClassType(method.getReturnType());
            Class<?>[] parameterTypes = method.getParameterTypes();
            Map<String, ParameterModel> parameterModelMap = Maps.newHashMap();
            for(Class<?> parameterType : parameterTypes){
                ParameterModel parameterModel = new ParameterModel();
                parameterModel.setName(parameterType.getCanonicalName());
                parameterModel.setType(parameterType.getSimpleName());
                parameterModel.setFullQualifiedName(parameterType.getTypeName());
                parameterModelMap.put(parameterType.getSimpleName(), parameterModel);
            }
            methods.put(method.getName(), methodModel);
        }
        return methods;
    }

    /**
     * 获取类变量的类型
     * @param clazz
     * @param name
     * @return
     */
    public static Type getVariableType(String name, Class clazz){
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields){
            if(ObjectUtils.nullSafeEquals(name.trim(), declaredField.getName())){
                return declaredField.getGenericType();
            }
        }
        return null;
    }

    /**
     * 获取指定方法的返回值类型
     * @param clazz
     * @param name
     * @param parameterCount
     * @return
     */
    public static String getMethodType(Class clazz, String name, int parameterCount){
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if(ObjectUtils.nullSafeEquals(name, method.getName()) && parameterCount == method.getParameterCount()){
                return method.getReturnType().getSimpleName();
            }
        }
        return null;
    }

    /**
     * 获取指定方法的返回值类型
     * @param clazz
     * @param name
     * @param methodModel
     * @return
     */
    public static String getMethodTypeByName(Class clazz, String name, MethodModel methodModel){
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            if(ObjectUtils.nullSafeEquals(name, method.getName()) && methodModel.getParameters().size() == method.getParameterCount()){
                int count = 0;
                Collection<ParameterModel> values = methodModel.getParameters().values();
                Class<?>[] parameterTypes = method.getParameterTypes();
                for(Class<?> parameterType : parameterTypes){
                    System.out.println("参数类型：" + parameterType.getSimpleName());
                    for(ParameterModel value : values){
                        if(ObjectUtils.nullSafeEquals(parameterType.getSimpleName(), value.getType())){
                            count++;
                        }
                    }
                }
                if(count == methodModel.getParameters().size()){
                    return method.getReturnType().getSimpleName();
                }
            }
        }
        return null;
    }

}
